package pyip.lib.mixtool.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.LongSerializationPolicy;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;

public class JsonUtil {
    private static class ByteArrayTypeAdapter extends TypeAdapter<byte[]> {
        @Override
        public void write(JsonWriter out, byte[] ar) throws IOException {
            if (ar == null) {
                out.nullValue();
                return;
            }
            out.value(BytesUtil.toHexString(ar));
        }

        @Override
        public byte[] read(JsonReader in) throws IOException {
            JsonToken t = in.peek();
            if (t == JsonToken.NULL) {
                in.nextNull();
                return null;
            }
            if (t == JsonToken.STRING) {
                String str = in.nextString();
                return BytesUtil.fromHexString(str);
            }
            ByteArrayOutputStream bout = new ByteArrayOutputStream(64);
            in.beginArray();
            while (in.hasNext()) {
                bout.write(in.nextInt());
            }
            in.endArray();
            bout.close();
            return bout.toByteArray();
        }

    }

    @SuppressWarnings("rawtypes")
    public static void main(String[] args) {
        Map<String, Object> m = new HashMap<String, Object>();
        List<String> l = new ArrayList<String>();
        l.add("x1");
        l.add("x2");
        m.put("list", l);

        String json = toJson(m);
        System.out.println(json);

        @SuppressWarnings("unchecked")
        Map<String, Object> rm = fromJson(json, Map.class);
        System.out.println(rm.size());
        System.out.println(((List) rm.get("list")).get(1));
    }

    public static final Gson gson = initGson(false);
    public static final Gson gsonForHtml = initGson(true);

    private static Gson initGson(boolean html) {
        GsonBuilder gb = new GsonBuilder();
        gb.setDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        if (!html) {
            gb.disableHtmlEscaping();
            // gb.generateNonExecutableJson();
            gb.setPrettyPrinting();
        }
        gb.registerTypeAdapter(byte[].class, new ByteArrayTypeAdapter());
        gb.setLongSerializationPolicy(LongSerializationPolicy.STRING);
        return gb.create();
    }

    public static String toJsonForHtml(Object obj) {
        return gsonForHtml.toJson(obj);
    }

    public static String toJson(Object obj) {
        return gson.toJson(obj);
    }

    public static void toJson(Object obj, Appendable out) {
        gson.toJson(obj, out);
    }

    public static <T> T fromJson(Reader in, Class<T> type) {
        if (in == null)
            return null;
        return gson.fromJson(in, type);
    }

    @SuppressWarnings("unchecked")
    public static <T> T fromJson(String str, Type type) {
        if (str == null || str.length() == 0) {
            if (str != null && type == String.class)
                return (T) (Object) "";
            return null;
        }
        return (T) gson.fromJson(str, type);

    }

    @SuppressWarnings("unchecked")
    public static <T> T fromJson(String str, Class<T> type) {
        return (T) fromJson(str, (Type)type);
    }

    @SuppressWarnings("unchecked")
    public static <T> T convert(Object obj, Class<T> type) {
        if (obj == null)
            return null;
        if (type.isInstance(obj))
            return (T) obj;
        return fromJson(toJson(obj), type);
    }
}
